#include <iostream>
using namespace std;
template<typename C>class Cref;
template<typename C>class String_sub;
template<typename C>class String_iter;

template<typename C>class String
{
    struct Srep;
    Srep* _rep;
public:
    class Range{};
    friend class String_sub<C>;
    friend class String_iter<C>;
    
    String();
    String(const C*);
    String(const String<C>&);
    String& operator=(const C*);
    String& operator=(const String<C>&);
    ~String();

    void check(int i)const;
    C read(int i)const;
    void write(int, C c);
    Cref<C> operator[](int i);
    C operator[](int i)const;
    const String<C> operator()(int left, int right)const;
    String_sub<C> operator()(int left, int right);

    int size()const;
    String<C>& operator+=(const String<C>&);
    String<C>& operator+=(const C*);
    template<typename Ch>
    friend ostream& operator<<(ostream&, const String<Ch>&);
    template<typename Ch>
    friend istream& operator>>(istream&, String<Ch>&);
    template<typename Ch>
    friend bool operator==(const String<Ch>& x, const Ch* s);
    template<typename Ch>
    friend bool operator==(const String<Ch>& x,const String<Ch>& y);
    template<typename Ch>
    friend bool operator!=(const String<Ch>& x,const Ch* s);
    template<typename Ch>
    friend bool operator!=(const String<Ch>& x,const String<Ch>& y);
    template<typename Ch>
    friend String operator+(const String<Ch>&,const String<Ch>&);
    template<typename Ch>
    friend String operator+(const String<Ch>&,const Ch*);
};
template<typename C>
class String_iter;

template<typename C>
class Cref
{
    friend class String<C>;
    friend class String_iter<C>;
    String<C>& _str;
    int _i;
    Cref(String<C>& str, int i):_str(str),_i(i){}
public:
    operator C(){//yield value
        return _str.read(_i);
    }
    void operator= (C c){//change value
        _str.write(_i,c);
    }
};
template<typename C>
class String_iter
{
    int _index;
    String<C>& _str;
public:
    String_iter<C>(String<C>& str):_str(str),_index(0){}
    Cref<C> next(){
        return Cref<C>(_str, _index++);
    }
    void reset(){
        _index = 0;
    }
};
template<typename C>
class String_sub
{
    friend class String<C>;
    String<C>& _str;
    int _left,_right;
    String_sub<C>(String<C>& str,int left, int right):
    _str(str),_left(left),_right(right){
    }
public:
    String<C>& operator=(const C* s);
    template<typename Ch>
    friend ostream& operator<<(ostream& os, const String_sub<Ch>& sub);
};

template<typename C>
struct String<C>::Srep
{
    C* s; //points to elements
    int sz;  //number of characters
    int n;   //reference count
    Srep(int nsz, const C* p){
        n = 1;
        sz = nsz;
        s = new C[sz+1];
        strcpy(s, p);
    }
    ~Srep(){
        delete[] s;
    }
    Srep* get_own_copy(){//clone if necessary
        if( n==1) return this;
        n--;
        return new Srep(sz,s);
    }
    void assign(int nsz, const C* p){
        if(sz != nsz){
            delete[] s;
            sz = nsz;
            s = new C[sz+1];
        }
        strcpy(s,p);
    }
private:
    Srep(const Srep&);
    Srep& operator=(const Srep&);
};
//Constructor
template<typename C>
String<C>::String()
{
    _rep = new Srep(0,"");
}
template<typename C>
String<C>::String(const String<C>& x)//copy constructor
{
    x._rep->n++;
    _rep = x._rep;
}
template<typename C>
String<C>::String(const C* s)//constructor
{
    _rep = new Srep(strlen(s), s);
}
template<typename C>
String<C>::~String()
{
    if(--_rep->n==0)delete _rep;
}
//copy assignment 1
template<typename C>
String<C>& String<C>::operator=(const String<C>& x)
{
    x._rep->n++;
    if(--_rep->n==0) delete _rep;
    _rep = x._rep;
    return *this;
}
//copy assignment 2
template<typename C>    
String<C>&String<C>::operator=(const C* s)
{
    if(_rep->n == 1)
        _rep->assign(strlen(s),s);
    else{
        _rep->n--;
        _rep = new Srep(strlen(s),s);
    }
    return *this;
}
template<typename C>    
void String<C>::check(int i)const
{
    if( i<0 || _rep->sz <= i)throw Range();
}
template<typename C>
C String<C>::read(int i)const
{
    return _rep->s[i];
}
template<typename C>
void String<C>::write(int i, C c)
{
    _rep=_rep->get_own_copy();
    _rep->s[i]=c;
}
template<typename C>
Cref<C> String<C>::operator[](int i)
{
    check(i);
    return Cref<C>(*this,i);
}
template<typename C>
C String<C>::operator[](int i)const
{
    check(i);
    return _rep->s[i];
}
template<typename C>
int String<C>::size()const
{
    return _rep->sz;
}
template<typename C>
const String<C> String<C>::operator()(int left, int right)const
{
    check(left);
    check(right);
    if(left <= right){
        C* buffer = new C[right-left+2];
        std::strncpy(buffer, _rep->s+left, right-left+1);
        buffer[right-left+1] = '\0';
        String<C> result(buffer);
        delete[] buffer;
        return result;
    }
    else{
        return String("");
    }
}

template<typename C>
String_sub<C> String<C>::operator()(int left, int right)
{
    return String_sub<C>(*this, left, right);
}
template<typename C>
bool operator==(const String<C>& x, const C* s)
{
    return strcmp(x._rep->s,s) == 0;
}
template<typename C>
bool operator==(const String<C>& x, const String<C>& y)
{
    return strcmp(x._rep->s, y._rep->s)==0;
}
template<typename C>
bool operator !=(const String<C>& x,const C* s)
{
    return strcmp(x._rep->s,s) != 0;
}
template<typename C>
bool operator!=(const String<C>&x, const String<C>& y)
{
    return strcmp(x._rep->s, y._rep->s) != 0;
}
template<typename C>
String<C> operator+(const String<C>& left, const String<C>& right)
{
    String<C> ret;
    size_t length = strlen(left._rep->s) + strlen(right._rep->s);
    char* buffer = new char[length+1];
    strcpy(buffer,left._rep->s);
    strcpy(buffer + strlen(left._rep->s), right._rep->s);
    ret._rep->assign(length+1, buffer);
    return ret;
}
template<typename C>
String<C> operator+(const String<C>&, const C*)
{
}
template<typename C>
ostream& operator<<(ostream& os, const String<C>& str)
{
    return os << str._rep->s;
}
template<typename C>
istream& operator>>(istream& is, String<C>& str)
{
    C buffer[1024];
    is >> buffer;
    str._rep->assign(strlen(buffer), buffer);
    return is;
}
template<typename C>
String<C>& String_sub<C>::operator=(const C* s)
{
    assert(strlen(s) == _right - _left);
    strcpy(_str._rep->s + _left, s);
    return _str;
}
template<typename C>
ostream& operator<<(ostream& os, const String_sub<C>& sub)
{
    for(int i = sub._left; i < sub._right; i++)
        os << sub._str[i];
    return os;
}
int main()
{
    String<char> str;
    str = "ZBC";
    cout << str << endl;

    str[1] = 'D';
    cout << str << endl;
}


    
